package sise.world.utils;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import sise.world.agent.AbstractAgent;
import sise.world.agent.BystretkaRoslinozernaAgent;
import sise.world.agent.BystretkaMiesozernaAgent;
import sise.world.agent.DrapieznikAgent;
import sise.world.agent.AbstractAgent.AgentType;
import sise.world.map.Field;

public class MapGenerator {

	// metoda tymczasowa, naiwna, trzeba zastapic czyms lepszym z uwzglednieniem
	// ilosci i rodzajem agentow
	private static SimulationConfiguration cfg;

	public static Field[][] generateRandomMap(int rows, int cols) {
		Field[][] map = new Field[rows][cols];
		Random r = new Random();
		for (int row = 0; row < rows; row++) {
			for (int col = 0; col < cols; col++) {
				Field field = new Field();
				if (col == 0 || col == cols - 1 || row == 0 || row == rows - 1) {
					field.setFieldType(Field.FieldType.MOUNTAIN);
				} else {
					// generate FieldType
					int next = r.nextInt(3);
					if (next == 0) {
						field.setFieldType(Field.FieldType.TREE);
					} else if (next == 1) {
						field.setFieldType(Field.FieldType.GROUND);
					} else if (next == 2) {
						field.setFieldType(Field.FieldType.WORM);
					}
					// generate AgentType
					// Local - 10%
					// Digger - 5%
					// Guard - 5%
					next = r.nextInt(100);
					AbstractAgent agent = null;
					if (next < 10) {
						agent = new DrapieznikAgent();
					} else if (next < 15) {
						agent = new BystretkaRoslinozernaAgent();
					} else if (next < 20) {
						agent = new BystretkaMiesozernaAgent();
					}
					if (agent != null) {
						field.setPresentAgent(agent);
						agent.setOwnField(field);
					}
				}
				map[row][col] = field;
			}
		}
		return map;
	}

	private static Field[][] generateRandomMap() {
		int rows = cfg.getRows();
		int cols = cfg.getCols();

		int foodPercentage = cfg.getFoodPercentage();
		int treePercentage = cfg.getTreePercentage();
		int orePercentage = cfg.getOrePercentage();
		int groundPercentage = cfg.getGroundPercentage();

		Field[][] map = new Field[rows][cols];
		Random r = new Random();

		List<Point> randomSequence = new ArrayList<Point>();
		for (int row = 0; row < rows; row++) {
			for (int col = 0; col < cols; col++) {
				randomSequence.add(new Point(row, col));
			}
		}
		Collections.shuffle(randomSequence, r);
		for (int i = 0; i != randomSequence.size(); i++) {
			int col = randomSequence.get(i).y;
			int row = randomSequence.get(i).x;
			Field field = new Field(new Point(row, col));
			if (col == 0 || col == cols - 1 || row == 0 || row == rows - 1) {
				field.setFieldType(Field.FieldType.MOUNTAIN);
			} else {
				// generate FieldType
				// normalize input
				int sum = groundPercentage + orePercentage + treePercentage
						+ foodPercentage;
				groundPercentage /= (sum / 100.0);
				orePercentage /= (sum / 100.0);
				treePercentage /= (sum / 100.0);
				foodPercentage /= (sum / 100.0);
				int oreCounter = 0;
				int treeCounter = 0;
				int foodCounter = 0;
				for (int k = -1; k != 2; k++) {
					for (int j = -1; j != 2; j++) {
						if (map[row + k][col + j] != null) {
							switch (map[row + k][col + j].getFieldType()) {
							case FOOD:
								foodCounter++;
								break;
							case WORM:
								oreCounter++;
								break;
							case TREE:
								treeCounter++;
								break;
							default:
								break;
							}
						}
					}
				}
				int newTreePercentage = treePercentage
						+ (int) ((Math
								.pow(cfg.getCreateTreeBase(), treeCounter) - cfg
								.getCreateTreeShift()) * 10);
				int newOrePercentage = orePercentage
						+ (int) ((Math.pow(cfg.getCreateWormBase(), oreCounter) - cfg
								.getCreateWormShift()) * 10);
				int newFoodPercentage = foodPercentage
						+ (int) ((Math
								.pow(cfg.getCreateFoodBase(), foodCounter) - cfg
								.getCreateFoodShift()) * 10);
				// normalize processed input
				int sumField = newTreePercentage + newOrePercentage
						+ newFoodPercentage + groundPercentage;
				newFoodPercentage *= ((100.0 - groundPercentage) / sumField);
				newOrePercentage *= ((100.0 - groundPercentage) / sumField);
				newTreePercentage *= ((100.0 - groundPercentage) / sumField);
				int next = r.nextInt(100);
				int resources = r.nextInt(20) + 1;
				if (next < newTreePercentage) {
					field.setFieldType(Field.FieldType.TREE);
					field.setResources(resources);
				} else if (next < newOrePercentage + newTreePercentage) {
					field.setFieldType(Field.FieldType.WORM);
					field.setResources(resources);
				} else if (next < newFoodPercentage + newOrePercentage
						+ newTreePercentage) {
					field.setFieldType(Field.FieldType.FOOD);
					field.setResources(resources);
				} else {
					field.setFieldType(Field.FieldType.GROUND);
				}
			}
			map[row][col] = field;
		}

		// generate agents
		List<Field> randomFields = new ArrayList<Field>();
		for (int row = 0; row < rows; row++) {
			for (int col = 0; col < cols; col++) {
				if (!(col == 0 || col == cols - 1 || row == 0 || row == rows - 1)) {
					randomFields.add(map[row][col]);
				}
			}
		}
		Collections.shuffle(randomFields, r);
		int mapFieldIndex = 0;
		String prePath = "rules/";
		for (AgentDescriptor ad : cfg.getAgents()) {
			for (int i = 0; i < ad.getQuantity(); i++) {
				AbstractAgent agent = null;
				if (ad.getAgentType().equals(AgentType.BYSTRETKA_ROSLINOZERNA)) {
					agent = new BystretkaRoslinozernaAgent();
				} else if (ad.getAgentType().equals(AgentType.DRAPIEZNIK)) {
					agent = new DrapieznikAgent();
				} else if (ad.getAgentType().equals(AgentType.BYSTRETKA_MIESOZERNA)) {
					agent = new BystretkaMiesozernaAgent();
				}
				if (agent != null) {
					agent.initClips(prePath + ad.getLogicPath());
					agent.setOwnField(randomFields.get(mapFieldIndex));
					randomFields.get(mapFieldIndex).setPresentAgent(agent);
					mapFieldIndex++;
				}
			}
		}
		return map;
	}

	public static Field[][] generateRandomMap(SimulationConfiguration cfg) {
		MapGenerator.cfg = cfg;
		return generateRandomMap();
	}

}
